package com.nervenets.web.controller.handler;

import com.nervenets.web.annotation.NeedValidation;
import com.nervenets.web.i18n.Translator;
import com.nervenets.utils.ReflectionUtil;
import com.nervenets.utils.ValidatorUtils;
import com.nervenets.web.validation.ValidateResult;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.ServletRequestUtils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * @author joe
 *         Created at 14-5-15 下午4:03
 */
public abstract class ApiParams {

    public List<String> getParamList() {
        List<String> params = new ArrayList<String>();
        final Class<? extends ApiParams> clazz = this.getClass();
        List<Field> fields = ReflectionUtil.getFieldInfo(null, clazz);
        for (Field field : fields) {
            field.setAccessible(true);
            final String fieldName = field.getName();
            params.add(fieldName);
        }
        return params;
    }

    public List<String> getParamNotes() {
        List<String> params = new ArrayList<String>();
        final Class<? extends ApiParams> clazz = this.getClass();
        List<Field> fields = ReflectionUtil.getFieldInfo(null, clazz);
        for (Field field : fields) {
            field.setAccessible(true);
            final Class<?> fieldType = field.getType();
            final String fieldTypeName = fieldType.getSimpleName();
            final String fieldName = field.getName();
            StringBuilder param = new StringBuilder(fieldName + ",类型" + (fieldType.isEnum() ? "枚举字符串" : fieldTypeName));
            if (fieldType.isEnum()) {
                Enum[] enums = ((Class<Enum>) fieldType).getEnumConstants();
                param.append("<br>{<ul>");
                for (Enum anEnum : enums) {
                    param.append("<li>").append(anEnum.name()).append(":").append(Translator.translate(anEnum)).append("</li>");
                }
                param.append("</ul>}<br>");
            }
            if (field.isAnnotationPresent(NeedValidation.class)) {
                final NeedValidation needValidation = field.getAnnotation(NeedValidation.class);
                switch (needValidation.type()) {
                    case EMPTY:
                        break;
                    case URL:
                        param.append(",链接格式");
                        break;
                    case EMAIL:
                        param.append(",邮箱格式");
                        break;
                    case NOTEMPTY:
                        param.append(",不能为空");
                        break;
                    case MOBILE:
                        param.append(",手机号码格式");
                        break;
                    case PHONENUMBER:
                        break;
                    case DIGITAL:
                        break;
                    case BIGDECIMAL:
                        break;
                    case MONEY:
                        break;
                    case BIRTHDATE:
                        break;
                    case FUTUREDATE:
                        break;
                    case AFTERTODAY:
                        break;
                    case DATE:
                        break;
                    case ZIPCODE:
                        break;
                    case NUMBER:
                        param.append(",数字类型");
                        break;
                    case FLOATNUMBER:
                        break;
                    case OPTIONALFLOATNUMBER:
                        break;
                    case POSITIVENUMBER:
                        param.append(",必传正整数");
                        break;
                    case FAX:
                        break;
                    case PASSWORD:
                        break;
                }
                if (!StringUtils.isEmpty(needValidation.description())) {
                    param.append(",").append(needValidation.description());
                }
            }
            params.add(param.toString());
        }
        return params;
    }

    public ValidateResult valid() throws IllegalAccessException {
        ValidateResult result = new ValidateResult(true);
        final Class<? extends ApiParams> clazz = this.getClass();
        List<Field> fields = ReflectionUtil.getFieldInfo(null, clazz);
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.isAnnotationPresent(NeedValidation.class)) {
                final NeedValidation needValidation = field.getAnnotation(NeedValidation.class);
                Object value = field.get(this);
                switch (needValidation.type()) {
                    case EMPTY:
                        break;
                    case URL:
                        if (null == value || !ValidatorUtils.isUrl(String.valueOf(value))) {
                            result.setValid(false);
                            result.addMessage(field.getName() + " is not a url!");
                        }
                        break;
                    case EMAIL:
                        if (null == value || !ValidatorUtils.isValidEmail(String.valueOf(value))) {
                            result.setValid(false);
                            result.addMessage(field.getName() + " is not a email!");
                        }
                        break;
                    case NOTEMPTY:
                        if (field.getType().isEnum() && null == value) {
                            result.setValid(false);
                            result.addMessage(field.getName() + " can not be right value!");

                        } else if (null == value || !(StringUtils.hasText(String.valueOf(value)))) {
                            result.setValid(false);
                            result.addMessage(field.getName() + " can not be empty!");
                        }
                        break;
                    case MOBILE:
                        if (null == value || !ValidatorUtils.isMobile(String.valueOf(value))) {
                            result.setValid(false);
                            result.addMessage(field.getName() + " is not a mobile number!");
                        }
                        break;
                    case PHONENUMBER:
                        break;
                    case DIGITAL:
                        break;
                    case BIGDECIMAL:
                        if (null == value || !ValidatorUtils.isFloatNumeric(String.valueOf(value))) {
                            result.setValid(false);
                            result.addMessage(field.getName() + " is not a float number!");
                        }
                        break;
                    case MONEY:
                        break;
                    case BIRTHDATE:
                        break;
                    case FUTUREDATE:
                        break;
                    case AFTERTODAY:
                        break;
                    case DATE:
                        break;
                    case ZIPCODE:
                        break;
                    case NUMBER:
                        if (null == value || !ValidatorUtils.isNumeric(String.valueOf(value))) {
                            result.setValid(false);
                            result.addMessage(field.getName() + " is not a number!");
                        }
                        break;
                    case FLOATNUMBER:
                        if (null == value || !ValidatorUtils.isFloatNumeric(String.valueOf(value))) {
                            result.setValid(false);
                            result.addMessage(field.getName() + " is not a float number!");
                        }
                        break;
                    case OPTIONALFLOATNUMBER:
                        break;
                    case POSITIVENUMBER:
                        try {
                            final long anNumber = Long.parseLong(String.valueOf(value));
                            if (anNumber <= 0) {
                                result.setValid(false);
                                result.addMessage(field.getName() + " is not a positive number!");
                            }
                        } catch (Exception e) {
                            result.setValid(false);
                            result.addMessage(field.getName() + " is not a positive number!");
                        }
                        break;
                    case FAX:
                        break;
                    case PASSWORD:
                        break;
                }
            }
        }
        return result;
    }

    protected ApiParams() {
    }

    public void init(HttpServletRequest request) throws IllegalAccessException {
        final Class<? extends ApiParams> clazz = this.getClass();
        List<Field> fields = ReflectionUtil.getFieldInfo(null, clazz);
        for (Field field : fields) {
            field.setAccessible(true);
            checkFieldValue(request, clazz, field);
        }
    }

    private void checkFieldValue(HttpServletRequest request, Class<? extends ApiParams> clazz, Field field) throws IllegalAccessException {
        final Class<?> fieldType = field.getType();
        final String fieldName = field.getName();
        Object value = null;
        if (fieldType.equals(Integer.class) || fieldType.equals(int.class)) {
            value = ServletRequestUtils.getIntParameter(request, fieldName, 0);
        } else if (fieldType.equals(Boolean.class) || fieldType.equals(boolean.class)) {
            value = ServletRequestUtils.getBooleanParameter(request, fieldName, false);
        } else if (fieldType.equals(Long.class) || fieldType.equals(long.class)) {
            value = ServletRequestUtils.getLongParameter(request, fieldName, 0L);
        } else if (fieldType.equals(Float.class) || fieldType.equals(float.class)) {
            value = ServletRequestUtils.getFloatParameter(request, fieldName, 0f);
        } else if (fieldType.equals(Double.class) || fieldType.equals(double.class)) {
            value = ServletRequestUtils.getDoubleParameter(request, fieldName, 0d);
        } else if (fieldType.isEnum()) {
            final String stringValue = ServletRequestUtils.getStringParameter(request, fieldName, null);
            if (!StringUtils.isEmpty(stringValue)) {
                try {
                    value = Enum.valueOf((Class<Enum>) Class.forName(fieldType.getName()), stringValue);
                } catch (Exception e) {
                    value = null;
                }
            }
        } else if (fieldType.equals(BigDecimal.class)) {
            value = BigDecimal.valueOf(ServletRequestUtils.getDoubleParameter(request, fieldName, 0d));
        } else {
            value = com.nervenets.utils.StringUtils.filterEmoji(ServletRequestUtils.getStringParameter(request, fieldName, null));
        }
        field.set(this, value);
    }
}
